/************************************************************************/
/*    Author: Scott Bevin                                               */
/************************************************************************/

#pragma once

#include <map>
#include <list>
#include "XInput\Input.h"
#include "XSystemComponents\XOgre\OgreRenderer.h"
#include "XTiming\Timer.h"

namespace XF
{
	class SystemComponent;

	class Application
	{
	protected:
		virtual bool OnInitialise(){return true;}
		virtual void OnHandleInput(double dT, Input *input){}
		virtual void OnUpdate(double dT){}
		virtual void OnShutDown(){}
		virtual bool PostInitializeComponents(){return true;}; //chris i added this so that things that need to be initialised after components can be done
		float mDeltaScale;
	private:
		
		bool mQuitGame;
		OgreRenderer *mOgre;

		Timer *mTimer;
		Input *mInput;

		typedef std::list<SystemComponent*> GameComponentList;
		typedef std::list<SystemComponent*>::iterator GameComponentListIt;
		typedef std::list<SystemComponent*>::reverse_iterator GameComponentListRevIt;

		typedef std::map<std::string, SystemComponent*> GameComponentMap;
		typedef std::map<std::string, SystemComponent*>::iterator GameComponentMapIt;

		GameComponentMap *mGameComponents;
		GameComponentList mGameComponentsList;

		bool InitializeFramework();

		void InitializeComponents();

		bool InitializeGraphics(std::string windowTitle, std::string resourceFile, bool initialiseResources);

		void AddDefaultComponents();

	public:
		Application();
		virtual ~Application();

		bool Initialize(std::string windowTitle, std::string resourceFile, bool initialiseResources);

		void Run();
		void ShutDown();

		void QuitGame() { mQuitGame = true; }

		void AddComponent(SystemComponent *component, std::string componentName);
		SystemComponent* GetComponent(std::string componentName);
		void RemoveComponent(SystemComponent *component);
		void RemoveComponent(std::string componentName){RemoveComponent(GetComponent(componentName));}

		OgreRenderer *GetRenderer(){return mOgre;}
		void Application::LogToCout( std::string message );
	};
}
